;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 介绍：	让芯片的定时器持续产生中断
; 备注：	1、复位和中断运行起始地址介绍详见STC官方文档《STC89C52系列单片机器件手册》
;			第6章 中断系统；
;			2、CSEG等所有Keil汇编伪指令的含义详见Keil安装目录下的文档
;			Keil_v5\C51\Hlp\a51.chm，文档里支持搜索；
;			3、8051 CPU内核的汇编指令及伪指令的介绍可参考大学的单片机原理等课程；
;			只想看原版8051指令集文档，不想看教材的话，可以搜索下载“Atmel 8051
;			Microcontrollers Hardware Manual”，或者“MCS ® 51 Family of 
;			Microcontrollers Architectural Overview”；本Git仓库doc文件夹内有下载
;			链接；
;			4、本工程默认使用Keil模拟器运行，无需硬件，按F7编译后，按Ctrl+F5开始
;			运行，在定时器中断处打上断点后可以持续触发中断；
; NOTE:		File format: UTF-8
; 作者		将狼才鲸
; 日期		2023-06-09
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; 包含寄存器定义头文件，也可以用#include <REGISTERS51.INC>，同样有效
$INCLUDE(REGISTERS51.INC)

	;;
	; 1、ORG的作用和CSEG AT的作用一样，指定后面代码在内存中存放的位置，
	; CSEG等是Keil开发环境的伪指令（其它编译器如开源的SDCC可能有不一样的伪指令）;
	; 2、十六进制立即数以H结尾
	ORG		0000H	; RAM的0地址是复位中断执行的入口，后面的一些地址是各中断的入口
	LJMP	RESET	; 长跳转指令可跳64KB内的地址（函数），类似的还有其它短跳的指令

	ORG		0003H	; 外部中断0
	LJMP	DEFAULT_INT

	ORG		000BH	; 定时器0
	LJMP	TIMER0_INT

	ORG		0013H	; 外部中断1
	LJMP	DEFAULT_INT

	ORG		001BH	; 定时器1
	LJMP	DEFAULT_INT

	ORG		0023H	; 外部中断2
	LJMP	DEFAULT_INT

	ORG		002BH	; 外部中断3
	LJMP	DEFAULT_INT

	;;
	; 80H之前的地址是R0~R7等通用寄存器地址、位寻址地址和RAM堆栈地址，
	; 80H及以后是SFR特殊功能寄存器

	; 标号以冒号:结尾，和C语言的函数名类似
RESET:	
	NOP	; 空指令，消耗一个时钟周期的时间，什么也不做
	; 汇编写寄存器时，可能会直接写个立即数；而用C语言写时，会使用各种MASK和宏定义，每个bit的功能都用
	; 宏定义表示清楚，不会像这样直接写个数字，还要自己在脑袋里拆分成bit思考是什么功能
	MOV IE, #00H	; 屏蔽所有中断
					; 立即数以#井号开头，H结尾，不以#开头也是可以编译运行的
	;;
	; 初始化定时器0，定时器相关寄存器详见《STC89C52系列单片机器件手册》“第7章+定时器/计数器”
	; 相关的寄存器有IE、IP、TCON、TMOD、TL0、TL1、TH0、TH1
	MOV TCON, #00H	; 先禁止定时器0和1
	MOV TMOD, #11H	; 定时器0和1都作为定时器，定时器始终开启，双8位定时器模式
	MOV TH0, #00H
	MOV TL0, #0FFH	; 定时器0定时256个时钟周期
	SETB TR0	; 定时器0开始计数
	MOV IE, #0FFH	; 使能所有中断

LOOP:	; 汇编函数不遇到RET指令会一直往下执行，所以主程序会进入下面的死循环
	NOP
	NOP
	NOP
	LJMP	LOOP

TIMER0_INT:
	NOP		; 你在此打一个断点，用Keil仿真器运行时能持续进入此中断
	RETI	; 中断函数返回

DEFAULT_INT:
	NOP
	RETI

	END ; 汇编文件必须以END结尾
